/*
 *	Copyright (C) 2008 CRIMERE
 *	Copyright (C) 2008 Jean-Marc Mercier
 *	
 *	This file is part of OTS (optimally transported schemes), an open-source library
 *	dedicated to scientific computing. http://code.google.com/p/optimally-transported-schemes/
 *
 *	CRIMERE makes no representations about the suitability of this
 *	software for any purpose. It is provided "as is" without express or
 *	implied warranty.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */



/*! \file ForwardDifference.h
    \brief Multidimensional generalization of finite difference forward operators.

	Multidimensional generalization of the classical forward difference operator
	\f[
			\Delta_{\overline{x}} u_i=\frac{u_i-u_{i-1}}{h}
	\f]
	The geometry is the unit cube \f$[0,1]^N\f$, where N is given by data::Dim
*/

#if !defined(_D_x_)
#define _D_x_
#include <src/math/Operators/FiniteDifferenceOperators.h>
#include <src/math/Operators/Delta.h>

/*! 
    \brief Common multidimensional behavior for all finite difference forward operators.

	Common multidimensional behavior for all finite difference forward operators, i.e.
	\f[
			\Delta_x u_i=\frac{u_{i+1}-u_i}{h}
	\f]
 
	This class is non compilable : it is used to check at compile time whether the forward difference operator has been implemented
	for a given set of data.
*/
template <class data, std::size_t = data::Dim, class V = smart_ptr<data>>
class D_x 
	: public FiniteDifferenceOperator<data,data,V>
 {
//! return " D_x u"  \f$.
		static std::string get_name(){return " D_x u";};
		OS_STATIC_CHECK(false); // to implement
};

/*! 
    \brief One dimensional specialization of difference forward operators.

	\f[
			\Delta_x u_i=\frac{u_{i+1}-u_i}{h}
	\f]
 */
template <class data, class V>
class D_x<data,1,V>  
	: public FiniteDifferenceOperator<data,data,V>
{
public :
		enum:std::size_t												{Order = 1};
		typedef Forward													Centered_Type;
		typedef typename data::Boundary_type							Boundary_type;
		
		typedef FiniteDifferenceOperator								Base;
		typedef  typename Base::Base_Cast								Base_Cast;
		typedef D_x														type;

//! return " D_x u"  \f$.
		static std::string get_name(){return " D_x u";};
		D_x( ) : operator_interface_(*this,make_2<base_value_type>(0.,1.)) {};
		D_x(const D_x & data) : operator_interface_(*this,make_2<base_value_type>(0.,1.)),  Base(data) {};
		D_x(const weight_set_type & data) :  operator_interface_(*this,make_2<base_value_type>(0.,1.)), Base(data) {};

		D_x(const Base_Cast &first) : operator_interface_(*this,make_2<base_value_type>(0.,1.)), Base(first)
		{};
		virtual ~D_x(){};
		D_x & operator = (const D_x & from) {
			Base::operator =(from);
			return *this;
		};
		virtual void update() {
			operator_interface_.update();
		};
		//! Optimized code for forward difference operator.
		virtual result_type operator()(typename argument_type from) const 
		{
			return ( (from<<1) - from )*from.size();
		};
		//! Factory method.
		virtual smart_ptr_type Create_Instance() const {
			return Create_Instance_helper_arg<type,weight_set_type>(&weight_set_);
		};
private :
		operator_interface<D_x,Order,Centered_Type,Boundary_type> operator_interface_;
};


/*! \brief Bind operator of forward difference operator D_x_traits

	This is the time Bind operator of forward difference operator D_x_traits, that is D_x_t(t,u)=D_x(u)
*/
template <class data, typename Time = OS_double >
struct D_x_t : public BindTimeOperator<D_x<data> ,Time > {

	typedef D_x_t															time_operator_type;
	typedef BindTimeOperator<time_operator_type ,Time >						Base;
	D_x_t(){};
};

/*! 
    \brief A finite difference operator with viscosity.

	This operator compute the following viscous forward difference operator
	\f[
			\frac{u_{i+1}-u_i}{h}+h\delta_{x\overline{x}}u_i
	\f]
	It is used to smears out solutions of Non linear hyperbolic equation resulting from Entropic schemes.
 */
template <class data>
class D_x_visc  
	: public D_x<data>
{
public :
		typedef D_x_visc									type;
		typedef D_x											Base;
		typedef typename Base::graph_type					graph_type;

		//! return " Wave u"\f$.
		static std::string get_name(){return " Wave_Viscos u";};
		D_x_visc( ) {};
		D_x_visc(const D_x_visc & from) : Delta_(from.Delta_), Base(from) {};
		D_x_visc(const weight_set_type & data) :  Base(data) {};
		D_x_visc(const Base_Cast &first) : Base(first)
		{};
		virtual ~D_x_visc(){};
		virtual void update() {
			Base::update();
			Delta_.set_state_variable(get_state_variable());
		};
		virtual result_type operator()(typename argument_type from) const 
		{
			return Base::operator()(from) + Delta_(from)/(from.size(1));
		};
		virtual const graph_type& get_graph() const {
			return Delta_.get_graph();
		};
		virtual smart_ptr_type Create_Instance() const {
			return Create_Instance_helper_arg<type,weight_set_type>(&weight_set_);
		};
		Delta<data, data::Dim>	Delta_;
};

/*! \brief Bind operator of Viscous forward difference operator

	This is the time Bind operator of the Viscous forward difference operator D_x_visc, that is D_x_visc_t(t,u)=D_x_visc(u)
*/
template <class data,typename Time = OS_double >
struct D_x_visc_t : public BindTimeOperator<D_x_visc<data> ,Time > {

	typedef D_x_visc_t												time_operator_type;
	typedef BindTimeOperator<time_operator_type ,Time >				Base;
};


#endif